<?php

class MRouter extends MSingleton {
    const ROUTE_PATH = 'path';
    const ROUTE_GET = 'get';
    const DEFAULT_ROUTE_VAR = 'r';
    const MODULE_ADMIN_ROUTE_VAR = 'module';

    public $defaultController = 'home';
    public $defaultAction = 'index';
    public $routeVar = self::DEFAULT_ROUTE_VAR;
    public $routeStyle = self::ROUTE_GET; //PATH don't work

    /**
     * Define the module, controller and action of the $request
     * @param MRequest $request : Request to route
     */
    public function route(MRequest $request) {
        $requestArray = parse_url($request->getUrl());

        $path = $requestArray['path'];
        $args = array();
        if (isset($requestArray['query'])) {
            parse_str($requestArray['query'], $args);
        }

        unset($requestArray);

        if ($this->routeStyle === self::ROUTE_PATH) {
            $baseArray = parse_url(Mandrill::getApp()->baseUrl);
            if (isset($baseArray['path'])) {
                $path = str_ireplace($baseArray['path'], '', $path);
            }
            unset($baseArray);
            $args = explode('/', $path);
            $args = array_filter($args);
            $args = array_values($args);
            if (isset($args[0])) {
                if (preg_match('/.php$/', $args[0]) > 0) {
                    unset($args[0]);
                }
            }
            $args = array_filter($args);
            $args = array_values($args);

//            print_r($args);
            if (count($args) >= 1) {
                $request->setModule($args[0]);
                if (isset($args[1]) && !empty($args[1])) {
                    $request->setController($args[1]);
                } else {
                    $request->setController($this->defaultController);
                }
                if (isset($args[2]) && !empty($args[2])) {
                    $request->setAction($args[2]);
                } else {
                    $request->setAction($this->defaultAction);
                }
            } else if (isset(Mandrill::getApp()->defaultModule)) {
                $request->setModule(Mandrill::getApp()->defaultModule);
                $request->setController($this->defaultController);
                $request->setAction($this->defaultAction);
            } else {
                unset($args);
                throw new MException(MTranslator::translate('mandrill.web.router.routeNotSpecified'));
            }
        } else {
            $route = array();
            if (array_key_exists($this->routeVar, $args)) {
                $route = explode('/', $args[$this->routeVar]);
                if (count($route) >= 1) {
                    $request->setModule($route[0]);
                    if (isset($route[1]) && !empty($route[1])) {
                        $request->setController($route[1]);
                    } else {
                        $request->setController($this->defaultController);
                    }
                    if (isset($route[2]) && !empty($route[2])) {
                        $request->setAction($route[2]);
                    } else {
                        $request->setAction($this->defaultAction);
                    }
                } else {
                    throw new MException(MTranslator::translate('mandrill.web.router.routeNotSpecified'));
                }
                unset($route);
                unset($args[$this->routeVar]);
            } else if (isset(Mandrill::getApp()->defaultModule)) {
                $request->setModule(Mandrill::getApp()->defaultModule);
                $request->setController($this->defaultController);
                $request->setAction($this->defaultAction);
            } else {
                throw new MException(MTranslator::translate('mandrill.web.router.routeNotSpecified'));
            }
        }

        $params = $this->_getParams($args);
        $request->setParams($params);
        unset($params);
        unset($args);
    }

    /**
     * Define the module, controller and action of the $request or return NULL if route is not specified
     * @param MRequest $request : Request to route
     * @return NULL : If route is not specified
     */
    public function getRoute(MRequest $request) {
        $requestArray = parse_url($request->getUrl());
        $path = (isset($requestArray['path']))?$requestArray['path']:NULL;
        $args = array();
        if (isset($requestArray['query'])) {
            parse_str($requestArray['query'], $args);
        }

        unset($requestArray);

        if ($this->routeStyle === self::ROUTE_PATH) {
            // TODO
            $baseArray = parse_url(Mandrill::getApp()->baseUrl);
            if (isset($baseArray['path'])) {
                $path = str_ireplace($baseArray['path'], '', $path);
            }
            unset($baseArray);
            $args = explode('/', $path);
            $args = array_filter($args);
            $args = array_values($args);
            if (isset($args[0])) {
                if (preg_match('/.php$/', $args[0]) > 0) {
                    unset($args[0]);
                }
            }
            $args = array_filter($args);
            $args = array_values($args);
//            print_r($args);
            if (count($args) >= 1) {
                $request->setModule($args[0]);
                if (isset($args[1]) && !empty($args[1])) {
                    $request->setController($args[1]);
                } else {
                    $request->setController($this->defaultController);
                }
                if (isset($args[2]) && !empty($args[2])) {
                    $request->setAction($args[2]);
                } else {
                    $request->setAction($this->defaultAction);
                }
                $params = $this->_getParams($args);
                $request->setParams($params);
                unset($params);
            } else if (isset(Mandrill::getApp()->defaultModule)) {
                $request->setModule(Mandrill::getApp()->defaultModule);
                $request->setController($this->defaultController);
                $request->setAction($this->defaultAction);
                $params = $this->_getParams($args);
                $request->setParams($params);
                unset($params);
            } else {
                $params = $this->_getParams($args);
                $request->setParams($params);
                unset($params);
                unset($args);
                return NULL;
            }
            unset($args);
        } else {
            $route = array();
            if (array_key_exists($this->routeVar, $args)) {
                $route = explode('/', $args[$this->routeVar]);
                if (count($route) >= 1) {
                    $request->setModule($route[0]);
                    if (isset($route[1]) && !empty($route[1])) {
                        $request->setController($route[1]);
                    } else {
                        $request->setController($this->defaultController);
                    }
                    if (isset($route[2]) && !empty($route[2])) {
                        $request->setAction($route[2]);
                    } else {
                        $request->setAction($this->defaultAction);
                    }
                    $params = $this->_getParams($args);
                    $request->setParams($params);
                    unset($params);
                } else {
                    return NULL;
                }
                unset($route);
                unset($args);
            } else if (isset(Mandrill::getApp()->defaultModule)) {
                $request->setModule(Mandrill::getApp()->defaultModule);
                $request->setController($this->defaultController);
                $request->setAction($this->defaultAction);
                $params = $this->_getParams($args);
                $request->setParams($params);
                unset($params);
            } else
                return NULL;
        }
    }

    /**
     * Create a route with the chosen style ('get' or 'path').
     * @param String $route
     * @param Array $params
     * @return String 
     */
    public static function createRoute($route, $params=array()) {
        $router = MRouter::getInstance();
        $routeArray = explode('/', $route);
        if ($router->routeStyle === self::ROUTE_PATH) {
            if (count($routeArray) < 3 || count($routeArray) > 4)
                throw new MException;
            else {
                return $route . $router->implodeParams($params, '/');
            }
        } else {
            return '?' . $router->routeVar . '=' . $route . $router->implodeParams($params);
        }
    }

    private function implodeParams($params = array(), $glue = '&') {
        if (!empty($params)) {
            $return = '';
            if ($glue == '&') {
                $equals = '=';
            } else {
                $equals = $glue;
            }
            foreach ($params as $key => $value) {
                $return .= $glue . $key . $equals . $value;
            }
            return $return;
        }
    }

    /**
     * Return params specified in the route
     * @param Array $args
     * @return Array : Array with two arrays : GET and POST 
     */
    private function _getParams($args = NULL) {
        $params = array();
        $get = array();
        foreach ($args as $key => $value) {
            $get[$key] = $value;
        }
        $params['get'] = $get;
        $params['post'] = $_POST;

        return $params;
    }

}

?>
